﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Perceiveit.Xml
{
    public abstract class XProperty<T> : XProperty
    {
        #region public interface

        /// <summary>
        /// Gets the Property Value for the specified entity
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public abstract T GetValue(XEntity entity);

        /// <summary>
        /// Sets the Property Value for the specified entity
        /// </summary>
        /// <param name="entity">The entity that will have its property set to the specified value</param>
        /// <param name="value">The value to set it to</param>
        public abstract void SetValue(XEntity entity, T value);

        /// <summary>
        /// Clears (removes) the Property value for the specified entity
        /// </summary>
        /// <param name="entity">The entity on which to clear the value</param>
        public abstract void ClearValue(XEntity entity);

        #endregion

        /// <summary>
        /// Protected constructor for the abstract XProperty class
        /// </summary>
        protected XProperty() { }




        /// <summary>
        /// Helper method to add a new Cell to the entity
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="node"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        protected XPropertyCell<T> RegisterNewCell(XEntity entity, XObject node, T value)
        {
            XPropertyCell<T> cell = new XPropertyCell<T>(value, node);
            entity.SetCell(this, cell);
            return cell;
        }

        protected bool TryGetCell(XEntity entity, out XPropertyCell<T> cell)
        {
            XPropertyCell objcell;
            if (entity.TryGetCell(this, out objcell))
            {
                cell = objcell as XPropertyCell<T>;
                return null != cell;
            }
            else
            {
                cell = null;
                return false;
            }

        }

        protected XElement GetXElement(XEntity entity, bool createIfNotExist)
        {
            XElement parent = entity.Element;

            XName name = this.Name;

            //is this bound to the parent node
            if (null == name)
                return parent;
            
            if (string.IsNullOrEmpty(name.NamespaceName) && !string.IsNullOrEmpty(parent.Name.NamespaceName))
                name = XName.Get(this.Name.LocalName, parent.Name.NamespaceName);

            XElement ele = null;
            if (parent.HasElements)
            {

                ele = parent.Element(name);
            }
            if (null == ele && createIfNotExist)
            {
                ele = new XElement(name);
                parent.Add(ele);
            }

            return ele;
        }

        protected XAttribute GetAttribute(XEntity entity, bool create)
        {
            XElement ele = entity.Element;
            
            
            XAttribute attr = ele.Attribute(this.Name);
            if (null == attr && create)
            {
                attr = new XAttribute(this.Name, string.Empty);
                ele.Add(attr);
            }
            return attr;
        }
    }
}
